/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年6月27日
 */
package com.massyframework.beanskin.runtime.nativelib;

import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.massyframework.beanskin.ModuleIdentifier;
import com.massyframework.beanskin.SimpleModuleIdentifier;
import com.massyframework.beanskin.util.exceptioncollect.ExceptionCollectUtils;
import com.massyframework.beanskin.util.localstore.LocalStore;
import com.massyframework.beanskin.util.nativelib.NativeLibraryUtils;
import com.massyframework.beanskin.util.nativelib.OSInformation;

/**
 * 原生代码库
 * @author huangkh
 *
 */
public final class NativeLibrary {
	
	private static final String PREFIX_LINUX        =  "lib";
	private static final String EXTENSION_LINUX     = ".so";
	
	private static final String PREFIX_WINDOWS      =  "lib";
	private static final String EXTENSION_WINDOWS   = ".dll";
	
	public static String LIBPATH;

	/**
	 * 构造方法
	 * @param name {@link String},动态库文件名（取掉操作系统，扩展名后的名称)
	 */
	public NativeLibrary(String name, LocalStore localStore) {
		Objects.requireNonNull(name, "\"name\" cannot be null.");
		Objects.requireNonNull(localStore, "\"localStore\" cannot be null.");
		LIBPATH = this.getNativeLibsPaths(name, this.getClass().getClassLoader(), localStore);
		//LIBPATH = "/home/huangkh/cpp-massy-new/secure/Release/libsecure.so";
		//LIBPATH = "C:\\Users\\11722\\git\\secure-window\\x64\\Release\\secure.dll";
	}
		
	/**
	 * 加载动态库
	 */
	public void load() {
		if (LIBPATH != null) {
			try {
				System.load(LIBPATH);
			}catch(Exception e) {
				e.printStackTrace();
				ExceptionCollectUtils.addException(e);
			}
		}else {
			throw new IllegalArgumentException("canot support operation system:".concat(OSInformation.getName()));
		}
	}
	
	/**
	 * 卸载动态库
	 */
	public void unload() {
		if (LIBPATH != null) {
			NativeLibraryUtils.unloadLibrary(LIBPATH, this.getClass().getClassLoader());
		}
	}
	
	String getLibPath() {
		return LIBPATH;
	}

	/**
     * 获取原生共享库类库路径
     * @param classLoader {@link ClassLoader}, 类加载器
     * @return {@link List}
     */
    private String getNativeLibsPaths(String name, ClassLoader classLoader, LocalStore localStore) {
    	String resource = this.calcutionLibPath(name);
    	if (resource == null) return null;
    	
        URL url = classLoader.getResource(resource);
        if (url != null){
        	ModuleIdentifier identifier = SimpleModuleIdentifier.createModuleIdentifierWithKernel();
        	Path path = localStore.getDeploymentDirectory(identifier).resolve("lib").resolve(this.getFileName(name));
            InputStream is = null;
            try{
                File temp = path.toFile();
	            if (!temp.exists()) {
	                is = url.openStream();
	
	                Files.copy(is, temp.toPath(), StandardCopyOption.REPLACE_EXISTING);
                }
                return temp.getCanonicalPath();
            }catch(Exception e){
            	Logger logger = LoggerFactory.getLogger(NativeLibrary.class);
            	if (logger.isErrorEnabled()) {
            		logger.error(e.getMessage(), e);
            	}
                ExceptionCollectUtils.addException(e);
            }
        }else {
        	throw new IllegalArgumentException("cannot found native library: ".concat(resource));
        }
        return null;
    }
    
    
    /**
     * 根据操作系统计算动态库文件全名
     * @return {@link List}
     */
    private String calcutionLibPath(String name){
        if (OSInformation.isLinux()) {
           return String.format("BEANSKIN-INF/native/%s/%s%s%s", "linux", PREFIX_LINUX, name, EXTENSION_LINUX);
        }
        
        if (OSInformation.isWindows()){
           return String.format("BEANSKIN-INF/native/%s/%s%s%s", "win", PREFIX_WINDOWS, name, EXTENSION_WINDOWS);
        }
        
        return null;
    }
    
    private String getFileName(String name) {
    	if (OSInformation.isLinux()) {
    		return "linux".concat(File.separator).concat(PREFIX_LINUX).concat(name).concat(".so");
    	}
    	
    	if (OSInformation.isWindows()){
    		return "win".concat(File.separator).concat(PREFIX_WINDOWS).concat(name).concat(".dll");
    	}
    	
    	return "unkonwon";
    }
}
